#include "String.h"
#include "StringBuilder.h"
#include "array/Array.hpp"
#include <string>
#include <vector>
#include <cstdint>
#include <stdexcept>
#include <codecvt>
#include <locale>
#include <cstring>

using namespace yzrilyzr_array;

namespace yzrilyzr_lang{
	String::String(const ByteArray & str, StringEncoding encoding){
		strData=new _StringData();
		refDoConstruct(strData);
		byte_to_codepoint((char *)str._array, str.length, encoding);
	}
	String::String(const ByteArray & str, u_index off, u_index len, StringEncoding encoding){
		strData=new _StringData();
		refDoConstruct(strData);
		byte_to_codepoint((char *)str._array + off, len, encoding);
	}
	String::String(const std::string & str, StringEncoding encoding){
		strData=new _StringData();
		refDoConstruct(strData);
		byte_to_codepoint(str.data(), str.length(), encoding);
	}
	String::String(const char * str, StringEncoding encoding){
		if(!str){
			strData=nullptr;
			return;
		}
		strData=new _StringData();
		refDoConstruct(strData);
		byte_to_codepoint(str, strlen(str), encoding);
	}
	String::String(const std::wstring & str){
		strData=new _StringData();
		refDoConstruct(strData);
		utf16w_to_codepoint(str.data(), str.length());
	}
	String::String(const wchar_t * str){
		if(!str){
			strData=nullptr;
			return;
		}
		strData=new _StringData();
		refDoConstruct(strData);
		utf16w_to_codepoint(str, std::wcslen(str));
	}
	String::String(const std::u16string & str){
		strData=new _StringData();
		refDoConstruct(strData);
		utf16_to_codepoint(str.data(), str.length());
	}
	String::String(const char16_t * str){
		if(!str){
			strData=nullptr;
			return;
		}
		strData=new _StringData();
		refDoConstruct(strData);
		utf16_to_codepoint(str, std::char_traits<char16_t>::length(str));
	}
	String::String(const wchar_t * str, u_index off, u_index len){
		if(!str){
			strData=nullptr;
			return;
		}
		strData=new _StringData();
		refDoConstruct(strData);
		utf16w_to_codepoint(str + off, len);
	}
	String::String(const char16_t * str, u_index off, u_index len){
		if(!str){
			strData=nullptr;
			return;
		}
		strData=new _StringData();
		refDoConstruct(strData);
		utf16_to_codepoint(str + off, len);
	}

	void String::byte_to_codepoint(const char * src, u_index len, StringEncoding srcEncoding){
		if(src == nullptr || len == 0)return;
		if(srcEncoding == UTF8 || srcEncoding == StringEncoding::LOCAL && is_local_encoding_utf8()){
			utf8_to_codepoint(src, len);
		} else if(srcEncoding == StringEncoding::LOCAL){
			std::string utf8_str=local_to_utf8(src, len);
			utf8_to_codepoint(utf8_str.c_str(), utf8_str.size());
		} else{
			throw UnsupportedEncodingException();
		}
	}
	ByteArray String::getBytes(StringEncoding encoding)const{
		std::string bytes=tostring(encoding);
		u_index len=bytes.length();
		ByteArray arr(len);
		memcpy(arr._array, bytes.data(), len);
		return arr;
	}

	void String::utf16w_to_codepoint(const wchar_t * src, u_index len){
		if(src == nullptr || len == 0)return;
		strData->code_points.reserve(len);
		for(u_index i=0; i < len; ){
			uint16_t w1=static_cast<uint16_t>(src[i]);
			if(w1 < 0xD800 || w1 > 0xDFFF){
				strData->code_points.push_back(static_cast<uint32_t>(w1));
				i+=1;
			} else if(w1 >= 0xD800 && w1 <= 0xDBFF){
				if(i + 1 < len){
					uint16_t w2=static_cast<uint16_t>(src[i + 1]);
					if(w2 >= 0xDC00 && w2 <= 0xDFFF){
						uint32_t code_point=((w1 - 0xD800) << 10) | (w2 - 0xDC00);
						code_point+=0x10000;
						strData->code_points.push_back(code_point);
						i+=2;
						continue;
					}
				}
				strData->code_points.push_back(0xFFFD);
				i+=1;
			} else{ // w1 >= 0xDC00 && w1 <= 0xDFFF
				strData->code_points.push_back(0xFFFD);
				i+=1;
			}
		}
	}
	void String::utf16_to_codepoint(const char16_t * src, u_index len){
		if(src == nullptr || len == 0)return;
		strData->code_points.reserve(len);
		for(u_index i=0; i < len; ){
			uint16_t w1=static_cast<uint16_t>(src[i]);
			if(w1 < 0xD800 || w1 > 0xDFFF){
				strData->code_points.push_back(static_cast<uint32_t>(w1));
				i+=1;
			} else if(w1 >= 0xD800 && w1 <= 0xDBFF){
				if(i + 1 < len){
					uint16_t w2=static_cast<uint16_t>(src[i + 1]);
					if(w2 >= 0xDC00 && w2 <= 0xDFFF){
						uint32_t code_point=((w1 - 0xD800) << 10) | (w2 - 0xDC00);
						code_point+=0x10000;
						strData->code_points.push_back(code_point);
						i+=2;
						continue;
					}
				}
				strData->code_points.push_back(0xFFFD);
				i+=1;
			} else{ // w1 >= 0xDC00 && w1 <= 0xDFFF
				strData->code_points.push_back(0xFFFD);
				i+=1;
			}
		}
	}
	void String::utf8_to_codepoint(const char * src, u_index len){
		strData->code_points.reserve(len);
		for(u_index i=0; i < len; ){
			uint32_t code_point=0;
			unsigned char c=src[i];
			if((c & 0x80) == 0){
				code_point=c;
				i+=1;
			} else if((c & 0xE0) == 0xC0){
				if(i + 1 >= len) break;
				code_point=((c & 0x1F) << 6) | (src[i + 1] & 0x3F);
				i+=2;
			} else if((c & 0xF0) == 0xE0){
				if(i + 2 >= len) break;
				code_point=((c & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
				i+=3;
			} else if((c & 0xF8) == 0xF0){
				if(i + 3 >= len) break;
				code_point=((c & 0x07) << 18) | ((src[i + 1] & 0x3F) << 12) |
					((src[i + 2] & 0x3F) << 6) | (src[i + 3] & 0x3F);
				i+=4;
			} else{
				i++;
				continue;
			}
			strData->code_points.push_back(code_point);
		}
	}

	const std::string String::codepoint_to_utf8()const{
		std::string result;
		for(uint32_t cp:strData->code_points){
			if(cp <= 0x7F){
				result+=static_cast<char>(cp);
			} else if(cp <= 0x7FF){
				result+=static_cast<char>(0xC0 | ((cp >> 6) & 0x1F));
				result+=static_cast<char>(0x80 | (cp & 0x3F));
			} else if(cp <= 0xFFFF){
				result+=static_cast<char>(0xE0 | ((cp >> 12) & 0x0F));
				result+=static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
				result+=static_cast<char>(0x80 | (cp & 0x3F));
			} else if(cp <= 0x10FFFF){
				result+=static_cast<char>(0xF0 | ((cp >> 18) & 0x07));
				result+=static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
				result+=static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
				result+=static_cast<char>(0x80 | (cp & 0x3F));
			}
		}
		return result;
	}
	const std::wstring String::codepoint_to_utf16w() const{
		std::wstring result;
		result.reserve(strData->code_points.size());
		for(uint32_t cp:strData->code_points){
			if(cp > 0x10FFFF){
				continue;
			}
			if(cp < 0xD800 || (cp >= 0xE000 && cp <= 0xFFFF)){
				result.push_back(static_cast<wchar_t>(cp));
			} else if(cp >= 0x10000){
				uint32_t offset=cp - 0x10000;
				wchar_t high_surrogate=static_cast<wchar_t>(0xD800 + (offset >> 10));
				wchar_t low_surrogate=static_cast<wchar_t>(0xDC00 + (offset & 0x3FF));
				result.push_back(high_surrogate);
				result.push_back(low_surrogate);
			}
		}
		return result;
	}
	const std::u16string String::codepoint_to_utf16() const{
		std::u16string result;
		result.reserve(strData->code_points.size());
		for(uint32_t cp:strData->code_points){
			if(cp > 0x10FFFF){
				continue;
			}
			if(cp < 0xD800 || (cp >= 0xE000 && cp <= 0xFFFF)){
				result.push_back(static_cast<char16_t>(cp));
			} else if(cp >= 0x10000){
				uint32_t offset=cp - 0x10000;
				char16_t high_surrogate=static_cast<char16_t>(0xD800 + (offset >> 10));
				char16_t low_surrogate=static_cast<char16_t>(0xDC00 + (offset & 0x3FF));
				result.push_back(high_surrogate);
				result.push_back(low_surrogate);
			}
		}
		return result;
	}

	const std::string String::tostring(StringEncoding dstEncoding)const{
		if(dstEncoding == UTF8 || dstEncoding == StringEncoding::LOCAL && is_local_encoding_utf8()){
			return codepoint_to_utf8();
		} else if(dstEncoding == LOCAL){
			return utf8_to_local(codepoint_to_utf8());
		} else{
			throw UnsupportedEncodingException();
		}
	}
	const std::wstring String::towstring()const{
		return codepoint_to_utf16w();
	}
	const std::u16string String::tou16string()const{
		return codepoint_to_utf16();
	}
	String::String(const Object & obj) :String(obj.toString()){}
	String & String::operator+=(const String & str){
		refDoCopyOnWrite();
		static const String nul=U_NULL_STRING;
		const String * pstr=(str == nullptr)?&nul:&str;
		if(*this == nullptr){
			strData=new _StringData();
			refDoConstruct(strData);
			strData->code_points.insert(strData->code_points.end(), nul.begin(), nul.end());
		}
		strData->code_points.insert(strData->code_points.end(), pstr->begin(), pstr->end());
		invalidateCache();
		return *this;
	}
	String & String::operator*=(u_index count){
		static const String nul=U_NULL_STRING;
		if(*this == nullptr){
			strData=new _StringData();
			refDoConstruct(strData);
			strData->code_points.insert(strData->code_points.end(), nul.begin(), nul.end());
		}
		if(strData->code_points.empty() || count == 1) return *this;
		refDoCopyOnWrite();
		if(count == 0){
			strData->code_points.clear();
			return *this;
		}
		// 防止count过大导致内存溢出
		if(std::numeric_limits<u_index>::max() / count < strData->code_points.size()){
			throw OutOfMemoryError("Duplicate count too large");
		}
		auto original=strData->code_points;
		strData->code_points.reserve(original.size() * count);
		for(u_index i=1; i < count; i++){
			strData->code_points.insert(strData->code_points.end(), original.begin(), original.end());
		}
		invalidateCache();
		return *this;
	}
	u_index String::lastIndexOf(const String & str, u_index fromIndex) const{
		u_index tgtCount=str.length();
		if(tgtCount == 0) return fromIndex <= (u_index)length()?fromIndex:length();
		u_index rightIndex=length() - tgtCount;
		if(fromIndex > rightIndex){
			fromIndex=rightIndex;
		}
		if(fromIndex < 0){
			return -1;
		}
		uint32_t lastChar=str[tgtCount - 1];
		u_index i=fromIndex;
		while(true){
			while(i >= 0 && (*this)[i] != lastChar){
				i--;
			}
			if(i < 0){
				return -1;
			}
			u_index j=i - 1;
			u_index start=j - (tgtCount - 1);
			u_index k=tgtCount - 2;
			while(j > start){
				if((*this)[j--] != str[k--]){
					i--;
					break;
				}
			}
			if(j == start){
				return start + 1;
			}
		}
	}
	String  String::toUpperCase()const{
		String s=clone();  // 克隆当前字符串，避免修改原对象
		auto & cp=s.strData->code_points;  // 获取字符数组引用
		uint32_t a='a', z='z';
		for(uint32_t & c : cp){
			if(c >= a && c <= z){  // 判断是否为小写字母
				c-=32;  // 小写转大写（ASCII 码差值为 32）
			}
		}
		return s;
	}
	String String::toLowerCase()const{
		String s=clone();  // 克隆当前字符串
		auto & cp=s.strData->code_points;
		uint32_t A='A', Z='Z';
		for(uint32_t & c : cp){
			if(c >= A && c <= Z){  // 判断是否为大写字母
				c+=32;  // 大写转小写（ASCII 码差值为 32）
			}
		}
		return s;
	}
	String String::trim() const{
		u_index len=length();
		if(len == 0) return *this;
		u_index start=0;
		while(start < len && strData->code_points[start] <= 0x20){
			++start;
		}
		if(start == len) return "";
		u_index end=len - 1;
		while(end > start && strData->code_points[end] <= 0x20){
			--end;
		}
		return substring(start, end + 1);
	}
	yzrilyzr_array::Array<String> String::split(const String & delimiter) const{
		// 空分隔符处理 - 按字符分割
		if(delimiter.length() == 0){
			yzrilyzr_array::Array<String> result(length());
			for(u_index i=0, j=result.length; i < j; ++i){
				result[i]=StringBuilder().appendCodePoint(codePointAt(i)).toString();
			}
			return result;
		}
		std::vector<String> result;
		u_index start=0;
		u_index end=indexOf(delimiter, start);
		while(end != -1){
			// 添加分隔符前的部分
			if(start != end){
				result.push_back(substring(start, end));
			} else{
				// 连续分隔符情况，添加空字符串
				result.push_back("");
			}

			// 跳过分隔符
			start=end + delimiter.length();

			// 查找下一个分隔符
			end=indexOf(delimiter, start);
		}

		// 添加最后一部分
		if(start < length())result.push_back(substring(start));
		return yzrilyzr_array::Array<String>(result);
	}

	u_index String::indexOf(const String & s, u_index offset) const{
		u_index sLen=s.length(), mLen=length() - offset;
		Array<u_index> next(sLen);//同样长度next
		u_index prefixLen=0;
		u_index i=1;//跳过第一个
		while(i < sLen){
			if(s[prefixLen] == s[i]) next[i++]=++prefixLen;
			else{
				if(prefixLen == 0) next[i++]=0;
				else prefixLen=next[prefixLen - 1];
			}
		}
		u_index ps=0;
		u_index pp=0;
		while(ps < mLen){
			if((*this)[ps + offset] == s[pp]){//模式匹配，增加index
				ps++;
				pp++;
			} else if(pp > 0) pp=next[pp - 1];//不匹配，且模式index已移动，模式index取next
			else ps++;//模式index为0，移动主index
			if(pp == sLen){
				return ps - pp + offset;//模式结束，完全匹配
			}
		}
		return -1;
	}
	String String::replace(const String & oldStr, const String & newStr) const{
		u_index index=0, p=0;
		StringBuilder result;
		while((index=indexOf(oldStr, index)) != -1){
			result+=substring(p, index) + newStr;
			p=index + oldStr.length();
			index=p;
		}
		result+=substring(p);
		return result;
	}
	class my_codecvt_byname : public std::codecvt_byname<wchar_t, char, std::mbstate_t>{
		public:
		explicit my_codecvt_byname(const char * name, u_index refs=0)
			: std::codecvt_byname<wchar_t, char, std::mbstate_t>(name, refs){}
		~my_codecvt_byname()=default;
	};
}